#![allow(unused)]
use super::*;

pub type DTSResult = core::result::Result<DTSInfo, &'static str>;

pub const TY_CONST: &str = "Const";
pub const TY_ENUM: &str = "Enum";
pub const TY_FUNC: &str = "Func";
pub const TY_TYPE: &str = "Type";
pub const TY_CONSTRUCTOR: &str = "Constructor";
pub const TY_STATIC_FUNC: &str = "StaticFunc";
pub const TY_OBJECT: &str = "Object";

pub struct DTSInfo {
	name: String,
	dts: String,
	owner: Option<Path>,
	ty: &'static str,
}
impl DTSInfo {
	pub fn take(self) -> (String, &'static str, String, Option<Path>) {
		(self.name, self.ty, self.dts, self.owner)
	}
}
pub trait IntoDTSInfo {
	fn with(self, name: String, ty: &'static str, owner: &Path) -> DTSInfo;
	fn without(self, name: String, ty: &'static str) -> DTSInfo;
	fn owner(self, name: String, ty: &'static str, owner: &Option<Path>) -> DTSInfo;
	fn lit_cstr(self) -> core::result::Result<LitCStr, TokenStream>;
}
impl IntoDTSInfo for String {
	fn with(self, name: String, ty: &'static str, owner: &Path) -> DTSInfo {
		DTSInfo {
			dts: self,
			name,
			owner: Some(owner.clone()),
			ty,
		}
	}
	fn without(self, name: String, ty: &'static str) -> DTSInfo {
		DTSInfo {
			name,
			dts: self,
			owner: None,
			ty,
		}
	}
	fn owner(self, name: String, ty: &'static str, owner: &Option<Path>) -> DTSInfo {
		DTSInfo {
			name,
			dts: self,
			owner: owner.clone(),
			ty,
		}
	}
	fn lit_cstr(self) -> core::result::Result<LitCStr, TokenStream> {
		let span = Span::call_site();
		use std::str::FromStr;
		let ret =
			std::ffi::CString::from_str(&self).map_err(|_| Error::new(span, format!("{} to CStr fail", self)).into_compile_error())?;
		Ok(LitCStr::new(&ret, span))
	}
}

pub trait TryDTS {
	fn try_ts(&self) -> Option<String>;
}
impl<T: TryDTS> TryDTS for Option<T> {
	fn try_ts(&self) -> Option<String> {
		self.as_ref().map(|v| v.try_ts()).flatten()
	}
}

impl TryDTS for Path {
	fn try_ts(&self) -> Option<String> {
		self.segments.last().map(|v| v.ident.ts())
	}
}
impl TryDTS for Pat {
	fn try_ts(&self) -> Option<String> {
		match self {
			Self::Ident(v) => Some(v.ident.ts()),
			_ => None,
		}
	}
}
impl TryDTS for Type {
	fn try_ts(&self) -> Option<String> {
		match self {
			Self::Path(v) => v.path.try_ts(),
			Self::Reference(v) => v.elem.try_ts(),
			_ => None,
		}
	}
}
impl TryDTS for ReturnType {
	fn try_ts(&self) -> Option<String> {
		match self {
			ReturnType::Default => None,
			ReturnType::Type(_, ty) => ty.try_ts(),
		}
	}
}

pub trait IntoDTS {
	fn ts(&self) -> String;
}
impl IntoDTS for Ident {
	fn ts(&self) -> String {
		self.to_string()
	}
}
impl IntoDTS for ItemFn {
	fn ts(&self) -> String {
		self.sig.ident.ts()
	}
}
impl IntoDTS for ItemConst {
	fn ts(&self) -> String {
		self.ident.ts()
	}
}
impl IntoDTS for ItemStatic {
	fn ts(&self) -> String {
		self.ident.ts()
	}
}
impl IntoDTS for ItemType {
	fn ts(&self) -> String {
		self.ident.ts()
	}
}
impl IntoDTS for DeriveInput {
	fn ts(&self) -> String {
		self.ident.ts()
	}
}
impl IntoDTS for Variant {
	fn ts(&self) -> String {
		self.ident.ts()
	}
}

pub trait Transform {
	fn ts(&self) -> String;
}
impl Transform for String {
	fn ts(&self) -> String {
		match self.as_str() {
			"f64" | "i64" | "u32" | "i32" | "number" => "number".into(),
			"String" | "string" => "string".into(),
			"bool" | "boolean" => "boolean".into(),
			"Undefined" | "undefined" => "undefined".into(),
			"Null" | "null" => "null".into(),
			_ => self.clone(),
		}
	}
}
